package com.abaddon.model;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import android.graphics.Path.FillType;

import com.google.android.maps.GeoPoint;

public class AbaddonDatabase {

	private String dir = "/mnt/sdcard/abaddon/";
	private String path = dir+"abaddonDatabase.abaddonDb";
	
	private File fileDir = null;
	private File file = null;
	
	private PrintWriter pw = null;
	private BufferedReader br = null;
	private FileReader fr = null;
	
	/**
	 * Establishes a connection to the Abaddon database.
	 */
	public AbaddonDatabase(){
		create();
	}
	
	private void create(){
		
		fileDir = new File(dir);
		if(!fileDir.exists()){
			fileDir.mkdir();
		}

		file = new File(path);
		if(!file.exists()){
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	/**
	 * Removes all entries in the database.
	 */
	public void empty(){
		
		if(file.exists()){
	
			String toPrint = "";
			
			try {
				pw = new PrintWriter(path);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			pw.write(toPrint);
			pw.flush();
			pw.close();
			
		}
	
	}

	/**
	 * Adds place into the database. If it already exists, the existing one will be overwritten.
	 */
	public void addPlace(Place place) {
		addPlace(place.getPoint().getLatitudeE6(), place.getPoint().getLongitudeE6(), place.getTitle(), place.getSnippet(), place.getCategoriesArray());
	}
	
	/**
	 * Adds place into the database. If it already exists, the existing one will be overwritten.
	 */
	public void addPlace(int latitude, int longitude, String title, String description, String[] categories){
		
		if(file.exists()){
	
			removePlace(title);
			
			String toPrint = "place:"+title+":"+latitude+":"+longitude+":"+description+":";
			for(int i = 0; i<categories.length; i++){
				toPrint+=categories[i]+":";
			}
			try {
				fr = new FileReader(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			br = new BufferedReader(fr);
			
			List<String> fullText = new ArrayList<String>();
	
			String line = null;
			try {
				while((line = br.readLine()) != null){
					fullText.add(line);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			fullText.add(toPrint);
			
			try {
				pw = new PrintWriter(path);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			for(int i = 0; i<fullText.size(); i++){
				pw.write(fullText.get(i)+"\n");
			}
			
			pw.flush();
			pw.close();
		
		}
			
	}
	
	/**
	 * Returns a place if it exists in the database
	 * 
	 * @param nameToFind - name to look for
	 * @return place if found, null if not
	 */
	public Place getPlace(String nameToFind){
		
		if(file.exists()){
			
			try {
				fr = new FileReader(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			br = new BufferedReader(fr);
			
			String[] result = null; 
			String line = null;
			
			try {
				while((line = br.readLine()) != null){
					String[] split = line.split(":");
					if(nameToFind.equals(split[1])){
						result = split; 
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				fr.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			String[] categ = null;
			if(result.length-5 > 0){
				categ = new String[result.length-5];
				for(int i = 5; i<result.length; i++){
					categ[i-5] = result[i]; 
				}
			}else{
				categ = new String[]{};
			}
			
			if(result != null){
				return new Place(new GeoPoint(Integer.parseInt(result[2]), Integer.parseInt(result[3])), result[1], result[4], categ);
			}else{
				return null;
			}
			
		}else{
			return null;
		}
		
	}
	
	/**
	 * Checks if the place exists in the database
	 * 
	 * @param nameToFind - place to look for
	 * @return true if place exists, false if not
	 */
	public boolean exists(String nameToFind){
		
		if(file.exists()){
	
			try {
				fr = new FileReader(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			br = new BufferedReader(fr);
			
			boolean found = false;
			
			String line = null;
			try {
				while((line = br.readLine()) != null && !found){
					String[] split = line.split(":");
					if(nameToFind.equals(split[1])){
						found = true; 
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				fr.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			return found;
			
		}else{
			return false;
		}
		
	}
	
	/**
	 * Removes entry with the given name, does nothing if the name dont exist
	 * 
	 * @param name - name to remove
	 */
	public void removePlace(String name){
		
		if(file.exists()){
		
			try {
				fr = new FileReader(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			br = new BufferedReader(fr);
			
			List<String> fullText = new ArrayList<String>();
			
			String line = null;
			try {
				while((line = br.readLine()) != null){
					String[] split = line.split(":");
					fullText.add(line);
					if(split[0].equals("place") && split[1].equals(name)){
						fullText.remove(fullText.size()-1);
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				pw = new PrintWriter(path);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			for(int i = 0; i<fullText.size(); i++){
				pw.write(fullText.get(i)+"\n");
			}
			
			pw.flush();
			
			try {
				fr.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}
	
	/**
	 * Removes setting if it exists, if not, nothing happens
	 * @param name - setting to remove
	 */
	public void removeSetting(String name){
		
		if(file.exists()){
		
			try {
				fr = new FileReader(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			br = new BufferedReader(fr);
			
			List<String> fullText = new ArrayList<String>();
			
			String line = null;
			try {
				while((line = br.readLine()) != null){
					String[] split = line.split(":");
					fullText.add(line);
					if(split[0].equals("setting") && split[1].equals(name)){
						fullText.remove(fullText.size()-1);
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				pw = new PrintWriter(path);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			for(int i = 0; i<fullText.size(); i++){
				pw.write(fullText.get(i)+"\n");
			}
			
			pw.flush();
			
			try {
				fr.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}
	
	/**
	 * @return - Returns number of entries in database
	 */
	public int getNumberOfEntries(){
		
		if(file.exists()){
		
			try {
				fr = new FileReader(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			br = new BufferedReader(fr);
			
			int lines = 0;
			
			try {
				while(br.readLine() != null){
					lines++;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				fr.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			return lines;
			
		}else{
			return 0;
		}

	}
	
	/**
	 * @return - Returns a list of all places in database, if no places exists, null is returned
	 */
	public List<Place> getAllPlaces(){
		if(file.exists()){
			try {
				fr = new FileReader(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			br = new BufferedReader(fr);

			List<Place> list = new ArrayList<Place>();
			
			String line = null;
			try {
				while((line = br.readLine()) != null){
					String[] result = line.split(":");
					if(result[0].equals("place")){
						
						String[] categ = null;
						if(result.length-5 > 0){
							categ = new String[result.length-5];
						}
						
						for(int i = 5; i<result.length; i++){
							categ[i-5] = result[i]; 
						}
						
						list.add(new Place(new GeoPoint(Integer.parseInt(result[2]), Integer.parseInt(result[3])), result[1], result[4], categ));
					}
				}
			} catch (NumberFormatException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				fr.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			return list;
		}else{
			return null;
		}
		
	}
	
	/**
	 * Adds setting to db. If setting already exist, it will be overwritten.
	 * @param settingName - name of setting
	 * @param value - value of setting
	 */
	public void addSetting(String settingName, String value){

		removeSetting(settingName);
		
		String toPrint = "setting:"+settingName+":"+value+":";
		
		if(file.exists()){

			try {
				fr = new FileReader(file);
				br = new BufferedReader(fr);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			List<String> fullText = new ArrayList<String>();
	
			String line = null;
			try {
				while((line = br.readLine()) != null){
					fullText.add(line);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			fullText.add(toPrint);
			
			try {
				pw = new PrintWriter(path);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			for(int i = 0; i<fullText.size(); i++){
				pw.write(fullText.get(i)+"\n");
			}
			
			pw.flush();
			pw.close();
			
		}
		
	} 
	
	/**
	 * Returns a setting if it exists in the database, if not, null us returned
	 * 
	 * @param nameToFind - name to look for
	 * @return place if found, null if not
	 */
	public String getSetting(String settingToFind){
		
		String result = null;
		
		if(file.exists()){
		
			try {
				fr = new FileReader(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			br = new BufferedReader(fr);
			 
			String line = null;
			
			try {
				while((line = br.readLine()) != null){
					String[] split = line.split(":");
					if(split[0].equals("setting") && settingToFind.equals(split[1])){
						result = split[2]; 
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				fr.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}

		return result;
		
	}
	
	/**
	 * Adds a bunch of categories, only adds nonexistent categories
	 */
	public void addCategories(List<String> categories){
		if(categories != null){
			for(int i = 0; i<categories.size(); i++){
				if(categories.get(i).length()>0){
					addCategory(categories.get(i));
				}
			}
		}
	}
	
	/**
	 * Adds category, if it does already exist, nothing happens
	 */
	public void addCategory(String category){
		
		if(file.exists()){

			try {
				fr = new FileReader(file);
				br = new BufferedReader(fr);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			List<String> fullText = new ArrayList<String>();
	
			String line = null;
			
			boolean categoriesExist = false;
			boolean alreadyExists = false;
			boolean added = false;

			try {
				while((line = br.readLine()) != null){
					String[] split = line.split(":");
					if(split.length>0 && split[0].equals("categories")){
						categoriesExist = true;
						if(!added && !alreadyExists){
							for(int i = 1; i<split.length; i++){
								if(split[i].equals(category)){
									alreadyExists=true;
								}
							}
							if(!alreadyExists){
								line+=(category+":");
								added = true;
							}
						}
					}
					fullText.add(line);
				}
				if(!categoriesExist){
					fullText.add("categories:"+category+":");
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				pw = new PrintWriter(path);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			for(int i = 0; i<fullText.size(); i++){
				pw.write(fullText.get(i)+"\n");
			}
			
			pw.flush();
			pw.close();
		
		}
			
	}

	/**
	 * @return - returns a list with all categories, if none are found, null will be returned
	 */
	public List<String> getAllCategories(){
		
		if(file.exists()){

			try {
				fr = new FileReader(file);
				br = new BufferedReader(fr);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			List<String> result = new ArrayList<String>();
	
			String line = null;
			try {
				while((line = br.readLine()) != null){
					String[] split = line.split(":");
					if(split.length>0 && split[0].equals("categories")){
						for(int i = 1; i<split.length; i++){
							if(split[i].length()>0){
								result.add(split[i]);
							}
						}
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			return result;
		}else{
			return null;
		}
			
	}

	/**
	 * Removes a category, if it does not exist, nothing will happen
	 */
	public void removeCategory(String category){
		
		if(file.exists()){

			try {
				fr = new FileReader(file);
				br = new BufferedReader(fr);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			List<String> fullText = new ArrayList<String>();
			String line = null;
			
			try {
				while((line = br.readLine()) != null){
					String[] split = line.split(":");
					if(split.length>0 && split[0].equals("categories")){
						String newLine = "categories:";
						for(int i = 1; i<split.length; i++){
							if(!split[i].equals(category)){
								newLine += split[i]+":";
							}
						}
						fullText.add(newLine);
					}else{
						fullText.add(line);
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				pw = new PrintWriter(path);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			for(int i = 0; i<fullText.size(); i++){
				pw.write(fullText.get(i)+"\n");
			}
			
			pw.flush();
			pw.close();
		
		}
	}
}
